package com.wrupple.muba.base.client.widgets.reports.histogram;

import java.util.ArrayList;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.ui.ResizeComposite;
import com.google.gwt.view.client.SelectionModel;
import com.google.inject.Provider;
import com.wrupple.muba.common.domain.HistogramModel;
import com.wrupple.muba.common.shared.services.HistogramDataProcessor;
import com.wrupple.muba.desktop.domain.CellPosition;
import com.wrupple.muba.util.client.layout.grid.histogram.HistogramCellPositioner;
import com.wrupple.muba.widget.client.view.OverlayPanel;
import com.wrupple.muba.widget.client.view.OverlayPanelImpl;

public class HistogramComposite extends ResizeComposite {

	class AtomicCellSelectionHandler implements ClickHandler {
		AtomicCell cell;

		public AtomicCellSelectionHandler(AtomicCell cell) {
			super();
			this.cell = cell;
		}

		@Override
		public void onClick(ClickEvent event) {
			if (selectionModel != null) {
				boolean currentState = selectionModel.isSelected(cell);
				selectionModel.setSelected(cell, !currentState);
			}
		}

	}

	private AtomicCell[] cells;

	private OverlayPanelImpl ovm;
	private HistogramDataProcessor processor;
	private Provider<? extends AtomicCell> factory;
	private HistogramCellPositioner currentPositioner;
	private SelectionModel<AtomicCell> selectionModel;
	private ArrayList<HistogramAnalysisOverlay> overlays;

	public HistogramComposite(Provider<? extends AtomicCell> cellFactory,
			HistogramDataProcessor overlay) {
		super();
		this.processor = overlay;
		this.factory = cellFactory;
		this.ovm = new OverlayPanelImpl();

		initWidget(ovm);
	}

	public HistogramComposite(Provider<? extends AtomicCell> cellFactory,
			HistogramDataProcessor pro,
			HistogramCellPositioner currentPositioner) {
		this(cellFactory, pro);
		setCurrentPositioner(currentPositioner);
	}

	public HistogramDataProcessor getHistogramProcessor() {
		return processor;
	}

	public HistogramCellPositioner getCurrentPositioner() {
		return currentPositioner;
	}

	public void setCurrentPositioner(HistogramCellPositioner currentPositioner) {
		this.currentPositioner = currentPositioner;
	}

	public void draw(int width, int height, double[] rawData,
			double intervalWidth) {
		HistogramDataProcessor histogramProcessor = getHistogramProcessor();
		HistogramModel model = histogramProcessor.buildHistogramModelWithData(
				rawData, intervalWidth);
		ovm.forceLayout();

		CellPosition[] cellPositions = drawAtomicData(width, height, model,
				rawData);

		if (this.overlays != null) {
			for (HistogramAnalysisOverlay overlay : this.overlays) {
				overlay.updateLayers(model, cellPositions, this);
			}
		}

		ovm.animate(600);
	}

	private CellPosition[] drawAtomicData(int width, int height,
			HistogramModel model, double[] data) {

		currentPositioner.initializeHistogamGrid(model, width, height);
		CellPosition[] cellPositions = new CellPosition[data.length];
		for (int i = 0; i < data.length; i++) {
			cellPositions[i] = currentPositioner.getPosition(i);
		}

		if (cells == null) {
			cells = new AtomicCell[cellPositions.length];
		}

		AtomicCell widget;
		CellPosition position;
		double entry;
		for (int i = 0; i < cellPositions.length; i++) {
			position = cellPositions[i];
			entry = data[i];
			widget = cells[i];

			if (widget == null) {
				widget = createWidget(entry, i);
				cells[i] = widget;
				ovm.addAtPixelPosition(widget, (int) position.getX(),
						(int) position.getY(), (int) position.getWidth(),
						(int) position.getHeight());
			} else {
				ovm.setWidgetPixelPosition(widget, (int) position.getX(),
						(int) position.getY(), (int) position.getWidth(),
						(int) position.getHeight());
			}

		}

		return cellPositions;
	}

	private AtomicCell createWidget(double entry, int entryIndex) {
		AtomicCell cell = factory.get();
		cell.asWidget().addDomHandler(new AtomicCellSelectionHandler(cell),
				ClickEvent.getType());
		cell.setEntry(entry, entryIndex);
		return cell;
	}

	public void addOverlay(HistogramAnalysisOverlay overlay) {
		if (this.overlays == null) {
			this.overlays = new ArrayList<HistogramAnalysisOverlay>();
		}
		this.overlays.add(overlay);
	}

	public OverlayPanel getOverlayPanel() {
		return this.ovm;

	}

	public AtomicCell getCell(int index) {
		return this.cells[index];
	}

	public void setEventBus(EventBus eventBus) {

		if (this.overlays != null) {
			for (HistogramAnalysisOverlay overlay : this.overlays) {
				overlay.setEventBus(eventBus);
			}
		}
	}

	public SelectionModel<AtomicCell> getSelectionModel() {
		return selectionModel;
	}

	public void setSelectionModel(SelectionModel<AtomicCell> selectionModel) {
		this.selectionModel = selectionModel;
	}

}